package org.dev.hi.hiui.recyclerview

import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import org.dev.hi.hiui.R
import org.dev.hi.hiui.item.HiAdapter
import org.dev.hi.library.log.HiLog

/**
 * Author WenPing
 * CreateTime 2021/4/19.
 * Description:这是一个RecyclerView的派生类，功能有更多的拓展
 */
open class HiRecyclerView @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null,
    defStyle: Int = 0
) : RecyclerView(context, attributeSet, defStyle) {

    private var loadMoreScrollListener: RecyclerView.OnScrollListener? = null

    private var footerView: View? = null

    private var isLoadingMore: Boolean = false;

    /**
     * 创建一个内部类，其中它的构造方法中传入一个Int类型的参数，和一个无参且无返回值的函数
     */
    inner class LoadMoreScrollListener(val prefetchSize: Int, val callback: () -> Unit) :
        RecyclerView.OnScrollListener() {
        //这里的强壮，因为在前面会有前置检查
        val hiAdapter = adapter as HiAdapter

        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            //需要根据当前的滑动状态 决定是否添加FooterView 要不要执行官上拉加载分页的动作
            if (isLoadingMore) return

            //咱们需要判断当前列表上已经显示的item的个数，如果列表上已显示的item的数量小于0
            val totalItemCount = hiAdapter.itemCount
            if (totalItemCount <= 0) return


            /**
             * 此时，咱们需要在滑动状态为拖动状态时判断要不要添加Footer
             * 目的就是为了防止列表滑动到底部，但是footerView还没显示出来
             * 1.如果需要判断列表是否能够滑动，那么问题来了，如何判断Recyclerview 是否可以继续向下滑动
             * Negative to check scrolling up, positive to check scrolling down.
             * 输入参数1表示向下滑动
             */
            val canScrollVertically = recyclerView.canScrollVertically(1)

            /**
             * 还有一种情况，列表已经滑动到底部了，但是分页失败了，怎么处理
             */

            val lastVisibleItem: Int = findLastVisibleItem(recyclerView)
            val firstVisibleItem: Int = findFirstVisibleItem(recyclerView)

            //如果最后可见的item的序号小于等于0 ，张家界返回
            if (lastVisibleItem <= 0) return

            /**
             * 列表不可滑动,但列表没有撑满屏幕,
             * 此时lastVisibleItem就等于最后一条item,
             * 为了避免这种能情况，还需要加firstVisibleItem!=0

             */
            val arriveBottom: Boolean =
                lastVisibleItem >= totalItemCount - 1 && firstVisibleItem > 0

            /**
             * 在拖动列表并且 支持可以向下滑动，或者当前已经滑动到最底下
             * 是允许分页的
             */
            if (newState == RecyclerView.SCROLL_STATE_DRAGGING && (canScrollVertically || arriveBottom)) {
                addFooterView()
            }

            //不能在滑动停止后才去添加footerView
            if (newState != RecyclerView.SCROLL_STATE_IDLE) return

            /**
             * 预加载，就是不需要等待，
             * 滑动到最后一个item的时候，就触发下一页的加载动作
             */

            val arrivePrefetchPosition = totalItemCount - lastVisibleItem <= prefetchSize

            if (!arrivePrefetchPosition) return

            isLoadingMore = true
            //调用传进来的无参无返回的函数
            callback()

        }

        private fun findFirstVisibleItem(recyclerView: RecyclerView): Int {
            //when 判断，根据当前的layoutmanager的类型来返回对应的 index
            when (val layoutManager = recyclerView.layoutManager) {
                is LinearLayoutManager -> {
                    return layoutManager.findFirstVisibleItemPosition()
                }
                is StaggeredGridLayoutManager -> {
                    return layoutManager.findFirstVisibleItemPositions(null)[0]
                }
            }
            return -1
        }

        private fun findLastVisibleItem(recyclerView: RecyclerView): Int {
            //when 判断，根据当前的layoutmanager的类型来返回对应的 index
            when (val layoutManager = recyclerView.layoutManager) {
                is LinearLayoutManager -> {
                    return layoutManager.findLastVisibleItemPosition()
                }
                is StaggeredGridLayoutManager -> {
                    return layoutManager.findLastVisibleItemPositions(null)[0]
                }
            }
            return -1
        }

        private fun addFooterView() {
            val footerView = getFooterView()

            /**
             * 避免在边界场景中 footerView还没冲recyclerView中移除掉，我们又调用addFooterView造成反复添加
             * 会报 add view must call removeView form it parent first exception
             */
            if (footerView.parent != null) {
                footerView.post {
                    //调用自己？
                    addFooterView()
                }
            } else {
                hiAdapter.addFooterView(footerView)
            }
        }

        private fun getFooterView(): View {
            if (footerView == null) {
                footerView = LayoutInflater.from(context)
                    .inflate(R.layout.layout_footer_loading, this@HiRecyclerView, false)
            }
            return footerView!!;
        }
    }

    /**
     * 是否支持加载更多
     */
    fun enableLoadingMore(callback: () -> Unit, prefetchSize: Int) {
        if (adapter !is HiAdapter) {
            HiLog.e("enable LoadMore must use HiAdapter")
            return
        }
        loadMoreScrollListener = LoadMoreScrollListener(prefetchSize, callback)
        addOnScrollListener(loadMoreScrollListener!!)
    }

    fun disableLoadMore() {
        if (adapter !is HiAdapter) {
            HiLog.e("disable LoadMore must use HiAdapter")
            return
        }
        val hiAdapter = adapter as HiAdapter
        footerView?.let {
            if (footerView!!.parent != null) {
                hiAdapter.removeFooterView(footerView!!)
            }
        }

        loadMoreScrollListener?.let {
            removeOnScrollListener(loadMoreScrollListener!!)
            loadMoreScrollListener = null
            footerView = null
            isLoadingMore = false
        }

    }

    fun isLoading(): Boolean = isLoadingMore

    fun loadFinished(success: Boolean) {
        if (adapter !is HiAdapter) {
            HiLog.e("loadFinished must use hiadapter")
            return
        }
        isLoadingMore = false
        val hiAdapter = adapter as HiAdapter
        if (!success) {
            footerView?.let {
                if (footerView!!.parent != null) {
                    hiAdapter.removeFooterView(footerView!!)
                } else {
                    //do nothing
                }
            }
        }
    }
}